#include "update.h"

/**
 * @description: 服务升级结构体
 * @param {char} *pcJson 上传要转换json
 * @param {ST_IOTA_LOG} *pcStatusDecs 转换后的结构体
 * @return {*}
 */
bool JsonToStruct_ServiceUpdate(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_UPDATE_PROBE_PARAM *st_param = pcStatusDecs->param;
            st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
            st_param->fileName = strdup(cJSON_GetObjectItem(param, "fileName")->valuestring);
            st_param->digestAlgorithm = strdup(cJSON_GetObjectItem(param, "digestAlgorithm")->valuestring);
            st_param->digest = strdup(cJSON_GetObjectItem(param, "digest")->valuestring);
            st_param->fileType = strdup(cJSON_GetObjectItem(param, "fileType")->valuestring);

            if (cJSON_HasObjectItem(param, "fileVersion"))
            {
                st_param->fileVersion = strdup(cJSON_GetObjectItem(param, "fileVersion")->valuestring);
            }
            else
            {
                st_param->fileVersion = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @description: 服务升级结构体
 * @param {char} *pcJson 上传要转换json
 * @param {ST_IOTA_LOG} *pcStatusDecs 转换后的结构体
 * @return {*}
 */
bool JsonToStruct_ServiceUpdate_V1(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_UPDATE_CONF_PARAM *st_param = pcStatusDecs->param;

            if (cJSON_HasObjectItem(param, "path"))
            {
                st_param->path = strdup(cJSON_GetObjectItem(param, "path")->valuestring);
            }
            else
            {
                st_param->path = NULL;
            }
            if (cJSON_HasObjectItem(param, "path"))
            {
                st_param->configName = strdup(cJSON_GetObjectItem(param, "configName")->valuestring);
            }
            else
            {
                st_param->configName = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @description: 固件升级结构体
 * @param {char} *pcJson 上传要转换json
 * @param {ST_IOTA_LOG} *pcStatusDecs 转换后的结构体
 * @return {*}
 */
bool JsonToStruct_FirmwareUpdate(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = NULL;
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_UPDATE_FIRMWARE_PARAM *st_param = pcStatusDecs->param;
            st_param->firmwareName = strdup(cJSON_GetObjectItem(param, "firmwareName")->valuestring);
            st_param->firmwareId = strdup(cJSON_GetObjectItem(param, "firmwareId")->valuestring);
            st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @description: 设备探针升级
 * @param {char} *pJson
 * @return {*}
 */
int ServiceUpdate(char *pJson, bool isUpdate)
{
    dzlog_info("ServiceUpdate start  %d", isUpdate);
    ST_IOTA_LOG log;
    IOTA_UPDATE_PROBE_PARAM param;
    log.param = &param;
    JsonToStruct_ServiceUpdate(pJson, &log);
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;
    int ret = checkAndCreateDirectory(UPDATE_FILE_PATH);
    if (ret == 0)
    {
        log_res.code = 500;
        isError = true;
        dzlog_error("create directory error");
        goto Uerror;
    }
    MemoryStruct oDataChunk;
    oDataChunk.memory = malloc(1); // 初始化内存
    oDataChunk.size = 0;
    char filename[100] = {0};
    // 升级完成
    if (isUpdate)
    {
        FILE *pipe;
        char buffer[128];
        pipe = popen("cat update.tmp", "r");
        if (!pipe)
        {
            dzlog_error("Failed to open pipe for command execution.\n");
            free(oDataChunk.memory);
            return 1;
        }

        // 读取命令输出的结果
        while (fgets(buffer, sizeof(buffer), pipe) != NULL)
        {
            dzlog_info("update %s", buffer);
        }

        // 关闭管道
        pclose(pipe);

        if (strncmp("success", buffer, 7) == 0)
        {
            log_res.body = "success update";
            log_res.code = 200;
        }
        else
        {
            log_res.body = "update error";
            log_res.code = 500;
            isError = true;
        }
        dzlog_info("升级成功");
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
        free_s(psJson); //isError为true，还不goto，会泄露，需要释放
        // 删除升级文件
        pipe = popen("rm -rf update.json update.tmp update", "r");
        while (fgets(buffer, sizeof(buffer), pipe) != NULL)
            ;
        // 关闭管道
        pclose(pipe);
    }
    else
    {
        // 文件下载
        sprintf(filename, "%s/%s", UPDATE_FILE_PATH, param.fileName);
        // if (param.fileLink)
        //{
        ProgressInfo info;
        strcpy(info.fileid, param.fileId);
        strcpy(info.filename, param.fileName);
        info.ret = 0;

        int ret = file_download(filename, &info);
        if (ret == -1)
        {
            dzlog_error("下载出错：无法连接到或登录到文件服务器");
            isError = true;
            log_res.code = 520;
            goto Uerror;
        }
        else if (ret == -2)
        {
            dzlog_error("下载出错：文件服务器无法查询到该文件");
            isError = true;
            log_res.code = 521;

            goto Uerror;
        }
        else if (ret == -3)
        {
            dzlog_error("下载出错：文件下载超时或出错");
            isError = true;
            log_res.code = 522;
            goto Uerror;
        }
        else if (ret == -4)
        {
            dzlog_error("下载出错：没有这个文件或id");
            isError = true;
            log_res.code = 523;
            goto Uerror;
        }
        else
        {
            // 校验sha256
            char hash[SHA256_DIGEST_LENGTH * 2 + 1];
            calculate_file_sha256(filename, hash);
            if (strcmp(hash, param.digest) != 0)
            {
                log_res.code = 420;
                isError = true;
                dzlog_error("Verification error:%s", hash);
                goto Uerror;
            }

            // 下载完成，开始升级
            log_res.code = 100;
            log_res.body = "now is updating";
            dzlog_info("Start Upgrade:%s", filename);
            StructToJson_LogUploadRes(&psJson, &log_res, true);
            ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
            // 简单存储json
            FILE *json = NULL;
            json = fopen("update.json", "wb+");
            if (json == NULL)
            {
                log_res.code = 500;
                char cTime1[128] = {0};
                int ret = systemDate2(cTime1);
                log_res.msgTime = cTime1;
                dzlog_error("json file error");
                goto Uerror;
            }
            fprintf(json, "%s", pJson);
            // 关闭文件
            fclose(json);
        }
        //}
        // else
        //{
        //    log_res.code = 500;
        //    dzlog_error("下载链接为空");
        //    isError = true;
        //    goto Uerror;
        //}
    }

Uerror:
    if (isError)
    {
        log_res.body = "update error";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }

Ufree:
    free(log.iMid);
    free(log.deviceSn);
    free(log.deviceID);
    free(log.msgTime);
    free(log.node);
    free(log.requestID);
    free(log.Servicename);
    free(log.zone);
    free(oDataChunk.memory);
    free_s(psJson);

    free(param.digest);
    free(param.digestAlgorithm);
    free(param.fileId);
    // free(param.fileLink);
    free(param.fileName);
    free(param.fileType);

    if (isUpdate == false)
    {
        char *tmp[1000] = {0};
        sprintf(tmp, "/bin/sh update.sh %s", filename);
        // 执行升级程序
        dzlog_info("Start system tmp:%s", tmp);
        system(tmp);
    }
    return 0;
}

/**
 * @description: 固件下载
 * @param {char} *arg
 * @return {*}
 */
int firmwareDownload(char *arg)
{
    dzlog_info("firmwareDownload start ");

    ST_IOTA_LOG *log = (ST_IOTA_LOG *)arg;
    IOTA_UPDATE_PROBE_PARAM *param = (IOTA_UPDATE_PROBE_PARAM *)log->param;
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log->deviceID;
    log_res.deviceSn = log->deviceSn;
    log_res.iMid = uid;
    log_res.node = log->node;
    log_res.replyId = log->iMid;
    log_res.requestID = log->requestID;
    log_res.zone = log->zone;
    bool isError = false;

    MemoryStruct oDataChunk;
    oDataChunk.memory = malloc(1); // 初始化内存
    oDataChunk.size = 0;
    char filename[128] = {0};
    char filenametemp[128] = {0};

    char fileid[100] = {0};
    strcpy(fileid, param->fileId);

    log_res.code = 100;

    StructToJson_AppDownLoadRes(&psJson, &log_res);
    int ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    free_s(psJson);
    // 文件名
    // 判断下文件名是否是以.bin结尾的
    if (strlen(param->fileName) >= 4)
    {
        if (strcmp(param->fileName + strlen(param->fileName) - 4, ".bin") == 0)
        {
            sprintf(filename, "%s", param->fileName);
        }
        else
        {
            sprintf(filename, "%s.bin", param->fileName);
        }
    }

    ProgressInfo info;
    strcpy(info.fileid, param->fileId);
    strcpy(info.filename, filename);
    info.ret = 0;

    // 文件下载
    sprintf(filenametemp, "%s/%s", "/userdata/tmp", filename);
    ret = file_download(filenametemp, &info);
    if (ret == -1)
    {
        dzlog_error("下载出错：无法连接到或登录到文件服务器");
        isError = true;
        log_res.code = 520;
        goto Uerror;
    }
    else if (ret == -2)
    {
        dzlog_error("下载出错：文件服务器无法查询到该文件");
        isError = true;
        log_res.code = 521;

        goto Uerror;
    }
    else if (ret == -3)
    {
        dzlog_error("下载出错：文件下载超时或出错");
        isError = true;
        log_res.code = 522;
        goto Uerror;
    }
    else if (ret == -4)
    {
        dzlog_error("下载出错：没有这个文件或id");
        isError = true;
        log_res.code = 523;
        goto Uerror;
    }
    else
    {
        // 校验sha256
        char hash[SHA256_DIGEST_LENGTH * 2 + 1];
        calculate_file_sha256(filenametemp, hash);
        if (strcmp(hash, param->digest) != 0)
        {
            log_res.code = 420;
            isError = true;
            dzlog_error("Verification error：%s", hash);
            goto Uerror;
        }
        log_res.body = "success";
        log_res.code = 200;
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Uerror:
    if (isError)
    {
        log_res.body = "error";
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log->iMid);
    free_s(log->deviceSn);
    free_s(log->deviceID);
    free_s(log->msgTime);
    free_s(log->node);
    free_s(log->requestID);
    free_s(log->Servicename);
    free_s(log->zone);
    free_s(oDataChunk.memory);
    free_s(psJson);

    free_s(param->digest);
    free_s(param->digestAlgorithm);
    free_s(param->fileId);
    free_s(param->fileName);
    free_s(param->fileType);
    free_s(log);
    free_s(param);
    return 0;
}

int PatchDownload(char *arg)
{
    dzlog_info("PatchDownload start ");

    ST_IOTA_LOG *log = (ST_IOTA_LOG *)arg;
    IOTA_UPDATE_PROBE_PARAM *param = (IOTA_UPDATE_PROBE_PARAM *)log->param;
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log->deviceID;
    log_res.deviceSn = log->deviceSn;
    log_res.iMid = uid;
    log_res.node = log->node;
    log_res.replyId = log->iMid;
    log_res.requestID = log->requestID;
    log_res.zone = log->zone;
    bool isError = false;

    MemoryStruct oDataChunk;
    oDataChunk.memory = malloc(1); // 初始化内存
    oDataChunk.size = 0;

    char filenametemp[128] = {0};

    char fileid[100] = {0};
    strcpy(fileid, param->fileId);

    log_res.code = 100;

    StructToJson_AppDownLoadRes(&psJson, &log_res);
    int ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    free_s(psJson);

    ProgressInfo info;
    strcpy(info.fileid, param->fileId);
    strcpy(info.filename, param->fileName);
    info.ret = 0;

    // 文件下载
    sprintf(filenametemp, "%s/%s", "/userdata/tmp/package", param->fileName);
    ret = file_download(filenametemp, &info);
    if (ret == -1)
    {
        dzlog_error("下载出错：无法连接到或登录到文件服务器");
        isError = true;
        log_res.code = 520;
        goto Uerror;
    }
    else if (ret == -2)
    {
        dzlog_error("下载出错：文件服务器无法查询到该文件");
        isError = true;
        log_res.code = 521;

        goto Uerror;
    }
    else if (ret == -3)
    {
        dzlog_error("下载出错：文件下载超时或出错");
        isError = true;
        log_res.code = 522;
        goto Uerror;
    }
    else if (ret == -4)
    {
        dzlog_error("下载出错：没有这个文件或id");
        isError = true;
        log_res.code = 523;
        goto Uerror;
    }
    else
    {
        // 校验sha256
        char hash[SHA256_DIGEST_LENGTH * 2 + 1];
        calculate_file_sha256(filenametemp, hash);
        if (strcmp(hash, param->digest) != 0)
        {
            log_res.code = 420;
            isError = true;
            dzlog_error("Verification error：%s", hash);
            goto Uerror;
        }
        log_res.body = "success";
        log_res.code = 200;
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Uerror:
    if (isError)
    {
        log_res.body = "error";
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log->iMid);
    free_s(log->deviceSn);
    free_s(log->deviceID);
    free_s(log->msgTime);
    free_s(log->node);
    free_s(log->requestID);
    free_s(log->Servicename);
    free_s(log->zone);
    free_s(oDataChunk.memory);
    free_s(psJson);

    free_s(param->digest);
    free_s(param->digestAlgorithm);
    free_s(param->fileId);
    free_s(param->fileName);
    free_s(param->fileType);
    free_s(log);
    free_s(param);
    return 0;
}

int ConfigDownalod(char *arg)
{
    dzlog_info("ConfigDownalod start ");

    ST_IOTA_LOG *log = (ST_IOTA_LOG *)arg;
    IOTA_UPDATE_PROBE_PARAM *param = (IOTA_UPDATE_PROBE_PARAM *)log->param;
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log->deviceID;
    log_res.deviceSn = log->deviceSn;
    log_res.iMid = uid;
    log_res.node = log->node;
    log_res.replyId = log->iMid;
    log_res.requestID = log->requestID;
    log_res.zone = log->zone;
    bool isError = false;

    MemoryStruct oDataChunk;
    oDataChunk.memory = malloc(1); // 初始化内存
    oDataChunk.size = 0;

    char filenametemp[128] = {0};

    char fileid[100] = {0};
    strcpy(fileid, param->fileId);

    log_res.code = 100;

    StructToJson_AppDownLoadRes(&psJson, &log_res);
    int ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    free_s(psJson);

    ProgressInfo info;
    strcpy(info.fileid, param->fileId);
    strcpy(info.filename, param->fileName);
    info.ret = 0;

    // 文件下载
    sprintf(filenametemp, "%s/%s", "/userdata/tmp/package", param->fileName);
    ret = file_download(filenametemp, &info);
    if (ret == -1)
    {
        dzlog_error("下载出错：无法连接到或登录到文件服务器");
        isError = true;
        log_res.code = 520;
        goto Uerror;
    }
    else if (ret == -2)
    {
        dzlog_error("下载出错：文件服务器无法查询到该文件");
        isError = true;
        log_res.code = 521;

        goto Uerror;
    }
    else if (ret == -3)
    {
        dzlog_error("下载出错：文件下载超时或出错");
        isError = true;
        log_res.code = 522;
        goto Uerror;
    }
    else if (ret == -4)
    {
        dzlog_error("下载出错：没有这个文件或id");
        isError = true;
        log_res.code = 523;
        goto Uerror;
    }
    else
    {
        // 校验sha256
        char hash[SHA256_DIGEST_LENGTH * 2 + 1];
        calculate_file_sha256(filenametemp, hash);
        if (strcmp(hash, param->digest) != 0)
        {
            log_res.code = 420;
            isError = true;
            dzlog_error("Verification error：%s", hash);
            goto Uerror;
        }
        log_res.body = "success";
        log_res.code = 200;
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Uerror:
    if (isError)
    {
        log_res.body = "error";
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log->iMid);
    free_s(log->deviceSn);
    free_s(log->deviceID);
    free_s(log->msgTime);
    free_s(log->node);
    free_s(log->requestID);
    free_s(log->Servicename);
    free_s(log->zone);
    free_s(oDataChunk.memory);
    free_s(psJson);

    free_s(param->digest);
    free_s(param->digestAlgorithm);
    free_s(param->fileId);
    free_s(param->fileName);
    free_s(param->fileType);
    free_s(log);
    free_s(param);
    return 0;
}

int terminalServiceUpdate(char *pJson)
{
    return ServiceUpdate(pJson, false);
}

/// @brief 固件下载
/// @param pJson
/// @return
int firmwareServiceDownload(char *pJson)
{
    dzlog_info("firmwareServiceDownload start ");

    ST_IOTA_LOG *log;
    IOTA_UPDATE_PROBE_PARAM *param;
    log = malloc(sizeof(char) * 2048);
    param = malloc(sizeof(char) * 1024);
    log->param = param;
    JsonToStruct_ServiceUpdate(pJson, log);

    // 分线程
    pthread_t thread;
    pthread_attr_t attr;

    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, firmwareDownload, (void *)log);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);

    return 0;
}

int firmwareServiceUpgrade(char *pJson)
{
    dzlog_info("firmwareServiceUpgrade start ");
    ST_IOTA_LOG log;
    IOTA_UPDATE_FIRMWARE_PARAM param;
    log.param = &param;
    JsonToStruct_FirmwareUpdate(pJson, &log);

    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;
    char cmd[128] = {0};
    int uninstall = 0;
    int ret = 0;
    char filename[128] = {0};

    //// 文件名
    //// 判断下文件名是否是以.bin结尾的
    // if (strlen(param.firmwareName) >= 10)
    //{
    //     if (strcmp(param.firmwareName + strlen(param.firmwareName) - 4, ".sysupdate") == 0)
    //     {
    //         sprintf(filename, "%s", param.firmwareName);
    //     }
    //     else
    //     {
    //         sprintf(filename, "%s.sysupdate", param.firmwareName);
    //     }
    // }

    sprintf(cmd, "sysupdate -o /userdata/tmp/%s", filename);
    dzlog_info("firmwareServiceUpgrade start 11 cmd:%s", cmd);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        dzlog_error("%s upgrade error", filename);
        log_res.code = 500;
        isError = true;
        goto Uerror;
    }
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), fp) != NULL)
    {
        // 处理命令输出
        dzlog_info("message = %s", buffer);
    }
    log_res.code = 200;
    StructToJson_LogUploadRes(&psJson, &log_res, 1);
    IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));

Uerror:
    if (isError)
    {
        StructToJson_LogUploadRes(&psJson, &log_res, 1);
        ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));
    }

Ufree:
    free(log.iMid);
    free(log.deviceSn);
    free(log.deviceID);
    free(log.msgTime);
    free(log.node);
    free_s(log.requestID);
    free(log.Servicename);
    free(log.zone);

    free(param.firmwareName);
    free(param.firmwareId);
    free(param.fileId);
    free_s(psJson);

    pclose(fp);
    return 0;
}

/// @brief 补丁包下载
/// @param pJson
/// @return
int actionPatchDownload(char *pJson)
{
    dzlog_info("actionPatchDownload start ");
    ST_IOTA_LOG *log;
    IOTA_UPDATE_PROBE_PARAM *param;
    log = malloc(sizeof(char) * 2048);
    param = malloc(sizeof(char) * 1024);
    log->param = param;
    JsonToStruct_ServiceUpdate(pJson, log);

    // 分线程
    pthread_t thread;
    pthread_attr_t attr;

    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, PatchDownload, (void *)log);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);

    return 0;
}

/// @brief 补丁包升级
/// @param pJson
/// @return
int actionPatchUpgrade(char *pJson)
{
    ST_IOTA_LOG log;
    IOTA_UPDATE_CONF_PARAM param;
    log.param = &param;
    JsonToStruct_ServiceUpdate_V1(pJson, &log);
    if (param.path != NULL && strlen(param.path) != 0)
    {
        char srcpath[256] = "/userdata/tmp/package/";
        char dstpath[256] = {0};
        char cmd[512] = {0};
        strcat(srcpath, param.configName);
        dzlog_info("actionConfigDownalod start 33 srcpath[%s]", srcpath);
        strcat(dstpath, param.path);
        strcat(dstpath, "/");
        strcat(dstpath, param.configName);
        dzlog_info("actionConfigDownalod start 44 dstpath[%s]", dstpath);
        sprintf(cmd, "mv %s %s", srcpath, dstpath);
        system(cmd);
    }

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;

    log_res.code = 200;
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    int ret = IOTA_SendMqtt("/v1/devices/system/response", psJson, strlen(psJson));

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.path);
    free_s(param.configName);

    free_s(psJson);
    return 0;
}

/// @brief 配置下载
/// @param pJson
/// @return
int actionConfigDownalod(char *pJson)
{
    dzlog_info("actionPatchDownload start ");
    ST_IOTA_LOG *log;
    IOTA_UPDATE_PROBE_PARAM *param;
    log = malloc(sizeof(char) * 2048);
    param = malloc(sizeof(char) * 1024);
    log->param = param;
    JsonToStruct_ServiceUpdate(pJson, log);

    // 分线程
    pthread_t thread;
    pthread_attr_t attr;

    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, ConfigDownalod, (void *)log);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);

    return 0;
}